

#include <llist.h>
#include <stdio.h>

void llist_init(llist_t *list){

  memset(list, 0, sizeof(llist_t));
  pthread_mutex_init(&list->lock, NULL);

}

llist_data_t llist_add(llist_t *list, llist_data_t data){

  pthread_mutex_lock(&list->lock);

  llist_bucket_t *start = (llist_bucket_t *)list;

  if (start->next == NULL){
    start->next = _llist_make_bucket(data);
    pthread_mutex_unlock(&list->lock);
    return data;
  }

  llist_bucket_t *next;
  LLIST_TRAV(list, next){
    if (!next->next){
      next->next = _llist_make_bucket(data);
      pthread_mutex_unlock(&list->lock);
      return data;
    }
  }

  return 0;

  pthread_mutex_unlock(&list->lock);

}

llist_bucket_t *_llist_make_bucket(llist_data_t data){

  llist_bucket_t *new = (llist_bucket_t *)malloc(sizeof(llist_bucket_t));
  memset(new, 0, sizeof(llist_bucket_t));
  new->data = data;
  return new;

}

llist_data_t llist_lock_get(llist_t *list, int offset){

  pthread_mutex_lock(&list->lock);
  llist_get(list, offset);
  pthread_mutex_unlock(&list->lock);

  return 0;

}

llist_data_t llist_get(llist_t *list, int offset){

  int i = 0;
  llist_bucket_t *next;
  LLIST_TRAV(list, next){
    if (i++ == offset){
      pthread_mutex_unlock(&list->lock);
      return next->data;
    }
  }

  return 0;

}

llist_data_t llist_del(llist_t *list, int offset){

  pthread_mutex_lock(&list->lock);

  llist_bucket_t *next, *prev = (llist_bucket_t *)list;
  int i = 0;

  LLIST_TRAV(list, next){
    if (i++ == offset){
      prev->next = next->next;
      llist_data_t data = next->data;
      _llist_destroy_bucket(next);
      pthread_mutex_unlock(&list->lock);
      return data;
    }
    prev = next;
  }

  pthread_mutex_unlock(&list->lock);
  return 0;

}

void _llist_destroy_bucket(llist_bucket_t *bucket){

  free(bucket);

}

int llist_len(llist_t *list){

  pthread_mutex_lock(&list->lock);

  llist_bucket_t *next;
  int len = 0;
  LLIST_TRAV(list, next){
    len++;
  }
  pthread_mutex_unlock(&list->lock);
  return len;

}

void _llist_print(llist_t *list){

  fprintf(stderr, "List len=%d List data:\n", llist_len(list));

  pthread_mutex_lock(&list->lock);
  
  llist_bucket_t *next;
  int i = 0;
  LLIST_TRAV(list, next){
    fprintf(stderr, "Elem=%d data=0x%lx\n", i++, next->data);
  }

  pthread_mutex_unlock(&list->lock);

}
